%{
	#include <stdio.h>
	#include <malloc.h>
	
	#include "structs.h"
	#include "declarations.h"
	
	extern int yylex(void);
	extern int yydebug=1;

	struct ExternalDeclarationList *root;
	
	#define YYERROR_VERBOSE 0	
 %}

%union {
        int int_const;
        char *string_const;
        char *id;
        
        struct Expression *expr;
        struct ExpressionList *exprList;
        struct Statement *stmt;
        struct StatementList *stmtList;
		struct DeclarationDefinition *decldef;
		struct DeclarationDefinitionList *decldefList;
		struct FunctionDefinition *func;
		struct Declarator *declarator;
		struct Type *type;
		struct VariableDeclaration *varDecl;
		struct VariableDeclarationList *varDeclList;
		struct EnumDeclaration *enumDecl;
		struct EnumeratorList *enumeratorList;
		struct LabeledStatement * lbldStmt;
		struct LabeledStatementList *lbldStmtList;
		struct ClassInfo *classInfo;
		struct ExternalDeclaration *extDecl;
		struct ExternalDeclarationList *program;
}

%type <expr>			expression empty_expression
%type <exprList> 		expression_list keyword_message
%type <stmt> 			statement compound_statement selection_statement iteration_statement  jump_statement
%type <stmtList> 		statement_list statement_list_ne
%type <decldef> 		method_declaration method_definition
%type <decldefList>		interface_declaration_list implementation_definition_list interface_declaration_list_ne implementation_definition_list_ne
%type <func> 			function_definition
%type <declarator> 		method_declarator
%type <type> 			type_specifier
%type <varDecl> 		variable_declaration
%type <varDeclList> 	variable_declaration_list parameter_list instance_variables keyword_declarator
%type <enumDecl> 		enum_declaration
%type <enumeratorList> 	enumerator_list
%type <lbldStmt> 		labeled_statement
%type <lbldStmtList> 	labeled_statement_list 
%type <classInfo> 		class_interface class_implementation
%type <extDecl>			external_declaration
%type <program>			translation_unit program_unit


%token <id> IDENTIFIER
%token <int_const> CONSTANT CHAR
%token <string_const> STRING_LITERAL
%token <character> CHARACTER
%token LE_OP EQ_OP
%token AND_OP OR_OP	
%token INT VOID ENUM NSSTRING
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR BREAK RETURN
%token INTERFACE IMPLEMENTATION END
%token SELF SUPER NEW

%start program_unit

%right '='
%left AND_OP OR_OP
%left EQ_OP
%left '<' LE_OP
%left '+' '-'
%left '*' '/' '%'
%left '!' UMINUS 
%left '[' ']' '.'
%nonassoc ')'

%%
//выражение
expression
		: expression '=' expression					{$$ = CreateBinaryExpr(ExprTypeAssign, 	$1, $3)}
		| expression OR_OP expression				{$$ = CreateBinaryExpr(ExprTypeOr, 		$1, $3)}
		| expression AND_OP expression				{$$ = CreateBinaryExpr(ExprTypeAnd, 	$1, $3)}
		| expression '<' expression					{$$ = CreateBinaryExpr(ExprTypeLt, 		$1, $3)}
		| expression LE_OP expression				{$$ = CreateBinaryExpr(ExprTypeLE, 		$1, $3)}
		| expression EQ_OP expression				{$$ = CreateBinaryExpr(ExprTypeEq, 		$1, $3)}
		| expression '+' expression					{$$ = CreateBinaryExpr(ExprTypePlus, 	$1, $3)}
		| expression '-' expression					{$$ = CreateBinaryExpr(ExprTypeMinus, 	$1, $3)}
		| expression '*' expression					{$$ = CreateBinaryExpr(ExprTypeMul, 	$1, $3)}
		| expression '/' expression					{$$ = CreateBinaryExpr(ExprTypeDiv, 	$1, $3)}
		| expression '%' expression					{$$ = CreateBinaryExpr(ExprTypeRem, 	$1, $3)}
		
		| '!' expression							{$$ = CreateUnaryExpr(ExprTypeNeg, $2)}
		| '-' expression %prec UMINUS				{$$ = CreateUnaryExpr(ExprTypeUMinus, $2)}
		
		| expression '[' expression ']'				{$$ = CreateBinaryExpr(ExprTypeArrayItemAccess, $1, $3)}
		
		| '(' expression ')'						{$$ = $2}
		
		| expression '.' IDENTIFIER					{$$ = CreateIntanceVariableAccessExpr($1, $3)}
		
		| IDENTIFIER '(' ')'						{$$ = CreateFunctionCallExpr($1, NULL)}
		| IDENTIFIER '(' expression_list ')'		{$$ = CreateFunctionCallExpr($1, $3)}
		
		| '[' expression IDENTIFIER ']'				{$$ = CreateMethodCallExpr(CallObjectTypeExpression, $2, $3)}
		| '[' SUPER IDENTIFIER ']'					{$$ = CreateMethodCallExpr(CallObjectTypeSuper, NULL, $3)}
		
		| '[' expression keyword_message ']'		{$$ = CreateMethodCallArgsExpr(CallObjectTypeExpression, $2, $3)}
		| '[' SUPER keyword_message ']'				{$$ = CreateMethodCallArgsExpr(CallObjectTypeSuper, NULL, $3)}
		
		| IDENTIFIER								{$$ = CreateIdentifierExpr($1)}
		| CONSTANT									{$$ = CreateConstantExpr($1)}
		| CHAR										{$$ = CreateCharExpr($1)}
		| STRING_LITERAL							{$$ = CreateStringExpr($1)}
		
		| NEW IDENTIFIER							{$$ = CreateNewExpr($2)}		
		| SELF										{$$ = CreateSelfExpr()}
		;											
// пустое выражение
empty_expression
		: /*empty*/									{$$ = NULL}
		| expression								{$$ = $1}
		;
//список аргументов выражения
expression_list
		: expression								{$$ = CreateExpressionList($1)}
		| expression_list ',' expression			{$$ = AddToExpressionList($1, $3)}
		;
//описание
variable_declaration
		: type_specifier IDENTIFIER						{$$ = CreateVariableDeclaration(VariableDeclarationTypeRegular, $1, $2, 0, NULL)}
		| type_specifier IDENTIFIER '[' CONSTANT ']'	{$$ = CreateVariableDeclaration(VariableDeclarationTypeRegular, $1, $2, $4/*???*/, NULL)}
		;
		
//список объявлений
variable_declaration_list
		: variable_declaration ';'								{$$ = CreateVariableDeclarationList($1)}
		| variable_declaration_list variable_declaration ';'	{$$ = AddToVariableDeclarationList($1, $2)}
		;
//стандартные типы
type_specifier
		: CHAR					{$$ = CreateType(TypeVariantChar, NULL)}
		| INT					{$$ = CreateType(TypeVariantInt, NULL)}
		| IDENTIFIER			{$$ = CreateType(TypeVariantClass, $1)}
		| ENUM IDENTIFIER		{$$ = CreateType(TypeVariantEnum, $2)}
		| NSSTRING				{$$ = CreateType(TypeVariantNSString, NULL)}
		;

//список значений в enum
enumerator_list
		: IDENTIFIER						{$$ = CreateEnumeratorList($1)}
		| enumerator_list ',' IDENTIFIER	{$$ = AddToEnumeratorList($1, $3)}
		;
		
//список параметров
parameter_list
		: variable_declaration						{$$ = CreateVariableDeclarationList($1)}
		| parameter_list ',' variable_declaration	{$$ = AddToVariableDeclarationList($1, $3)}
		;

//описание enum
enum_declaration
		: ENUM IDENTIFIER '{' enumerator_list '}' ';'	{$$ = CreateEnumDeclaration($2, $4)}
		;

//выражение
statement
		: compound_statement		{$$ = $1}
		| expression ';'			{$$ = CreateExprStatement($1)}
		| selection_statement		{$$ = $1}
		| iteration_statement		{$$ = $1}
		| jump_statement			{$$ = $1}
		| variable_declaration ';'	{$$ = CreateVariableDeclarationStatement($1)}
		;
//список операторов(не пустой)
statement_list_ne
		: statement						{$$ = CreateStatementList($1)}
		| statement_list_ne statement	{$$ = AddToStatementList($1, $2)}
		;
//список операторов
statement_list
		: /*empty*/					{$$ = NULL}
		| statement_list_ne			{$$ = $1}
		;
//кейс-стейтменты
labeled_statement
		: CASE expression ':' statement_list	{$$ = CreateLabeledStatement(LabeledStatementTypeCase, $2, $4)}
		| DEFAULT ':' statement_list			{$$ = CreateLabeledStatement(LabeledStatementTypeDefault, NULL, $3)}
		;
//список кейс-стейтментов
labeled_statement_list
		: labeled_statement							{$$ = CreateLabeledStatementList($1)}
		| labeled_statement_list labeled_statement	{$$ = AddToLabeledStatementList($1, $2)}
		;
// составной оператор
compound_statement
		: '{' statement_list '}'	{$$ = CreateCompoundStatement($2)}
		;
//операторы выбора
selection_statement
		: IF '(' expression ')' statement							{$$ = CreateIfStatement($3, $5, NULL)}
		| IF '(' expression ')' statement ELSE statement			{$$ = CreateIfStatement($3, $5, $7)}
		| SWITCH '(' expression ')' '{' labeled_statement_list '}'	{$$ = CreateSwitchStatement($3, $6)}
		;
//оператора повторения
iteration_statement
		: WHILE '(' expression ')' statement												{$$ = CreateWhileStatement(StmtTypeWhile, $3, $5)}
		| DO statement WHILE '(' expression ')' ';'											{$$ = CreateWhileStatement(StmtTypeDoWhile, $5, $2)}
		| FOR '(' empty_expression ';' empty_expression ';' empty_expression ')' statement	{$$ = CreateForStatement($3, $5, $7, $9)}
		;
//операторы перехода
jump_statement
		: BREAK ';'				{$$ = CreateJumpStatement(StmtTypeBreak, NULL)}
		| RETURN ';'			{$$ = CreateJumpStatement(StmtTypeReturn, NULL)}
		| RETURN expression ';'	{$$ = CreateJumpStatement(StmtTypeReturn, $2)}
		;
//!!!главный узел
program_unit
		: translation_unit		{root = $1;}
		;

translation_unit
		: external_declaration						{$$ = CreateExternalDeclarationList($1)}
		| translation_unit external_declaration		{$$ = AddToExternalDeclarationList($1, $2)}
		;
//внешние объявления
external_declaration
		: function_definition		{$$ = CreateFuncExternalDeclaration($1)}
		| class_interface			{$$ = CreateClassExternalDeclaration(ExternalDeclarationInterface, $1)}
		| class_implementation		{$$ = CreateClassExternalDeclaration(ExternalDeclarationImplementation, $1)}
		| enum_declaration			{$$ = CreateEnumExternalDeclaration($1)}
		;
		
// определение функции
function_definition
		: type_specifier IDENTIFIER '(' ')' compound_statement					{$$ = CreateFunctionDefinition($1, $2, NULL, $5)}
		| type_specifier IDENTIFIER '(' parameter_list ')' compound_statement	{$$ = CreateFunctionDefinition($1, $2, $4, $6)}
		| VOID IDENTIFIER '(' ')' compound_statement							{$$ = CreateFunctionDefinition(CreateType(TypeVariantVoid, NULL), $2, NULL, $5)}
		| VOID IDENTIFIER '(' parameter_list ')' compound_statement				{$$ = CreateFunctionDefinition(CreateType(TypeVariantVoid, NULL), $2, $4, $6)}
		;
//описание класса
class_interface
		: INTERFACE IDENTIFIER instance_variables interface_declaration_list END					{$$ = CreateClassInfo(ClassInfoTypeDeclaration, $2, NULL, $3, $4)}			
		| INTERFACE IDENTIFIER ':' IDENTIFIER instance_variables interface_declaration_list END		{$$ = CreateClassInfo(ClassInfoTypeDeclaration, $2, $4, $5, $6)}
		;
//реализация класса
class_implementation
		: IMPLEMENTATION IDENTIFIER implementation_definition_list END		{$$ = CreateClassInfo(ClassInfoTypeDefinition, $2, NULL, NULL, $3)}
		;
//переменные класса!
instance_variables
		: /*empty*/								{$$ = NULL}
		| '{' variable_declaration_list '}'		{$$ = $2}
		| '{' '}'								{$$ = NULL}
		;
// объявление метода
method_declaration
		: '-' '(' type_specifier ')' method_declarator ';'		{$$ = CreateMethodDeclarationDefinition(DeclTypeMethodDeclaration, $3, $5, NULL)}
		| '-' '(' VOID ')' method_declarator ';'				{$$ = CreateMethodDeclarationDefinition(DeclTypeMethodDeclaration, CreateType(TypeVariantVoid, NULL), $5, NULL)}
		;
// объявление методов
interface_declaration_list
		: /*empty*/							{$$ = NULL}
		| interface_declaration_list_ne		{$$ = $1}
		;

interface_declaration_list_ne
		: method_declaration								{$$ = CreateDeclarationDefinitionList($1)}
		| interface_declaration_list_ne method_declaration	{$$ = AddToDeclarationDefinitionList($1, $2)}
		;
// описание метода
method_definition
		: '-' '(' type_specifier ')' method_declarator compound_statement  		{$$ = CreateMethodDeclarationDefinition(DeclTypeMethodDefinition, $3, $5, $6)}
		| '-' '(' VOID ')' method_declarator compound_statement					{$$ = CreateMethodDeclarationDefinition(DeclTypeMethodDefinition, CreateType(TypeVariantVoid, NULL), $5, $6)}
		;
// описание методов
implementation_definition_list
		: /*empty*/								{$$ = NULL}
		| implementation_definition_list_ne		{$$ = $1}
		;
implementation_definition_list_ne
		: method_definition									{$$ = CreateDeclarationDefinitionList($1)}
		| implementation_definition_list_ne method_definition	{$$ = AddToDeclarationDefinitionList($1, $2)}
		;
// описание/объявление метода без аргументов и с
method_declarator
		: IDENTIFIER			{$$ = CreateDeclarator(DeclaratorTypeId, $1, NULL)}
		| keyword_declarator	{$$ = CreateDeclarator(DeclaratorTypeKeyword, NULL, $1)}
		;
// описание аргументов метода
keyword_declarator
		: IDENTIFIER ':' '(' type_specifier ')' IDENTIFIER						{$$ = CreateVariableDeclarationList(CreateVariableDeclaration(VariableDeclarationTypeKeyword, $4, $1, 0, $6))}
		| keyword_declarator IDENTIFIER ':' '(' type_specifier ')' IDENTIFIER	{$$ = AddToVariableDeclarationList($1, CreateVariableDeclaration(VariableDeclarationTypeKeyword, $5, $2, 0, $7))}
		;
// набор аргументов к сообщению
keyword_message
		: IDENTIFIER ':' expression						{$$ = CreateMessagesList($1, $3)}
		| keyword_message IDENTIFIER ':' expression		{$$ = AddToMessagesList($1, $2, $4)}
		;
%%
